package com.boco.ibssystem.common.provider;

import com.google.common.base.Stopwatch;
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;

import java.math.BigDecimal;
import java.sql.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

public class DataProvider {

    private Long id;

    private String dataSourceName;

    private String type;

    private String driverClassName;

    private String jdbcUrl;

    private String username;

    private String password;

    private HikariDataSource dataSource;

    private static final ConcurrentHashMap<Long, DataProvider> DATASOURCE_POOL = new ConcurrentHashMap<>();

    private DataProvider(Long id, String dataSourceName, String type, String driverClassName, String jdbcUrl, String username, String password) {
        HikariConfig hikariConfig = new HikariConfig();

        this.id = id;
        this.dataSourceName = dataSourceName;
        this.type = type;
        this.driverClassName = driverClassName;
        this.jdbcUrl = jdbcUrl;
        this.username = username;
        this.password = password;

        hikariConfig.setDriverClassName(this.driverClassName);
        hikariConfig.setJdbcUrl(this.jdbcUrl);
        hikariConfig.setUsername(this.username);
        hikariConfig.setPassword(this.password);
        hikariConfig.setPoolName(this.type + "-" + this.id);
        dataSource = new HikariDataSource(hikariConfig);
        DATASOURCE_POOL.put(this.id, this);
    }

    public static DataProvider getInstance(Long id) {
        return DATASOURCE_POOL.get(id);
    }

    public static DataProvider buildDataProvider(Long id, String dataSourceName, String type, String driverClassName, String jdbcUrl, String username, String password) {
        return new DataProvider(id, dataSourceName, type, driverClassName, jdbcUrl, username, password);
    }

    public List<HashMap<String, Object>> getData(String sql) throws Exception {
        Stopwatch stopwatch = Stopwatch.createStarted();
        List<HashMap<String, Object>> result = new ArrayList<>();
        try (Connection con = getConnection(); Statement ps = con.createStatement(); ResultSet rs = ps.executeQuery(sql)) {
            ResultSetMetaData metaData = rs.getMetaData();
            int columnCount = metaData.getColumnCount();
            String[] rowname = new String[columnCount];
            int[] rowType = new int[columnCount];
            for (int i = 0; i < columnCount; i++) {
                rowType[i] = metaData.getColumnType(i + 1);
                rowname[i] = metaData.getColumnLabel(i + 1);
            }
            while (rs.next()) {
                HashMap<String, Object> column = new HashMap<>();
                for (int i = 0; i < rowname.length; i++) {
                    column.put(rowname[i], columnHelper(rs, i + 1, rowType[i]));
                }
                result.add(column);

            }
        } catch (Exception e) {
            throw new Exception("ERROR:" + e.getMessage(), e);
        }
        stopwatch.stop();
        return result;
    }

    public Float getFeiYong(String sql) throws Exception {
        Stopwatch stopwatch = Stopwatch.createStarted();
        Float feiyong = null;
        try {
            Connection con = getConnection();
            Statement ps = con.createStatement();
            ResultSet rs = ps.executeQuery(sql);
            while (rs.next()){
                feiyong = rs.getFloat(1);
            }
        } catch (Exception e) {
            throw new Exception("ERROR:" + e.getMessage(), e);
        }
        stopwatch.stop();
        return feiyong;
    }

    private Object columnHelper(ResultSet rs, int index, int rowType) throws SQLException {
        switch (rowType) {
            case 2:
            case 6:
                BigDecimal bigDecimal = rs.getBigDecimal(index);
                return bigDecimal.doubleValue();
            case 12:
                return new Date(rs.getDate(index).getTime());
            case 180:
            case 181:
            case 231:
                return new Date(rs.getTimestamp(index).getTime());
            default:
                return rs.getString(index);

        }
    }

    private Connection getConnection() throws SQLException {
        return this.dataSource.getConnection();
    }

    public Map<String, Float> getFeiYongByGroup(String sql) throws Exception {
        Stopwatch stopwatch = Stopwatch.createStarted();
        Map<String, Float> map = new HashMap<>();
        try {
            Connection con = getConnection();
            Statement ps = con.createStatement();
            ResultSet rs = ps.executeQuery(sql);
            //检索此 ResultSet 对象的列的编号、类型和属性。
            ResultSetMetaData rsmd = rs.getMetaData();
            //得到当前的列数
            int colCount = rsmd.getColumnCount();
            while (rs.next()){
                map.put(rs.getString(2),rs.getFloat(1));
            }
        } catch (Exception e) {
            throw new Exception("ERROR:" + e.getMessage(), e);
        }
        stopwatch.stop();
        return map;
    }
}
